﻿Option Explicit On
Imports System.Xml

Public Class frmEditConstants
    ' James D. Zoll
    ' 
    ' the Edit Constants form displays to the user as a place to
    ' enter values for the various values that are considered 'constant'
    ' throughout all calculations.  This includes things like the amount
    ' of hit rating per percent of hit, the overall hit or spell caps, the
    ' relative value of ArP, etc.  The form will read and write to the data_constants.xml
    ' file in the CommonAppDataPath directory.

    ' Two variables to keep track of the save state of the weights.
    Private saved As Boolean
    Private prevValue As Double

    Public Sub Load_Constants()
        ' When the form loads, the file should be loaded and its
        ' values put into the correct text fields.  No other
        ' logic or checking takes place here.
        Try
            ' Variables to hold the basic XML information.
            Dim m_xmld As XmlDocument
            Dim m_nodelist As XmlNodeList
            Dim m_node As XmlNode
            Dim buildinfo As FileVersionInfo = FileVersionInfo.GetVersionInfo(Windows.Forms.Application.ExecutablePath)
            Dim msgResult As DialogResult

            ' On the first run or after user deletion the data_constants file will not exist in the
            ' application data directory.  Check this and copy the file if necessary to avoid
            ' writing to Program Files.  Load the correct file when the copy is complete.
            m_xmld = New XmlDocument()
            If System.IO.File.Exists(Windows.Forms.Application.CommonAppDataPath & "\data_constants.xml") = False Then
                System.IO.File.Copy(Windows.Forms.Application.StartupPath & "\data_constants.xml", Windows.Forms.Application.CommonAppDataPath & "\data_constants.xml")
            End If

            m_xmld.Load(Windows.Forms.Application.CommonAppDataPath & "\data_constants.xml")
            m_nodelist = m_xmld.SelectNodes("/constants")
            m_node = m_nodelist(0)

            ' After loading the correct file, check the version.  If it is from a prior version of 
            ' DK Optimize, offer the user the option to replace the file with the more recent
            ' default values from the main appliaction directory.
            If m_node.Attributes.GetNamedItem("version").Value <> buildinfo.ProductVersion Then
                msgResult = MessageBox.Show("Constants appear to be from a different version of DK Optimize.  Would you like to reload the most current default values? Existing values will be lost.", "DK Optimize", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2)
                If msgResult = Windows.Forms.DialogResult.Yes Then
                    System.IO.File.Delete(Windows.Forms.Application.CommonAppDataPath & "\data_constants.xml")
                    System.IO.File.Copy(Windows.Forms.Application.StartupPath & "\data_constants.xml", Windows.Forms.Application.CommonAppDataPath & "\data_constants.xml")
                    m_xmld = New XmlDocument
                    m_xmld.Load(Windows.Forms.Application.CommonAppDataPath & "\data_constants.xml")
                    m_nodelist = m_xmld.SelectNodes("/constants")
                    m_node = m_nodelist(0)
                End If
            End If

            ' Read the values from the XML and set the text controls to the appropriate
            ' values.  When this is complete, set the saved state to true.
            txtMeleeHit.Text = Double.Parse(m_node.ChildNodes.Item(0).InnerText, System.Globalization.CultureInfo.InvariantCulture)
            txtSpellHit.Text = Double.Parse(m_node.ChildNodes.Item(1).InnerText, System.Globalization.CultureInfo.InvariantCulture)
            txtMeleeCap.Text = Double.Parse(m_node.ChildNodes.Item(2).InnerText, System.Globalization.CultureInfo.InvariantCulture)
            txtSpellCap.Text = Double.Parse(m_node.ChildNodes.Item(3).InnerText, System.Globalization.CultureInfo.InvariantCulture)
            txtExpertise.Text = Double.Parse(m_node.ChildNodes.Item(4).InnerText, System.Globalization.CultureInfo.InvariantCulture)
            txtExpertiseCap.Text = Double.Parse(m_node.ChildNodes.Item(5).InnerText, System.Globalization.CultureInfo.InvariantCulture)
            txtArP.Text = Double.Parse(m_node.ChildNodes.Item(6).InnerText, System.Globalization.CultureInfo.InvariantCulture)
            setSaved(True)
        Catch
            MessageBox.Show("There was an unspecified error while attempting to read data_constants.xml. Please reinstall DK Optimize", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
            End
        End Try
    End Sub

    Private Sub Save_Constants()
        ' This function does the work of saving the constants
        ' back to the data_constants.xml file in the AppData location on
        ' the system.
        Try
            ' Variable declaration for the xmlWriter and version information.
            Dim xmlWriter As New XmlTextWriter(Windows.Forms.Application.CommonAppDataPath & "\data_constants.xml", System.Text.Encoding.UTF8)
            Dim BuildInfo As FileVersionInfo = FileVersionInfo.GetVersionInfo(Windows.Forms.Application.ExecutablePath)

            ' Constants are written to the XML document and the saved state
            ' is set to true.
            xmlWriter.WriteStartDocument()
            xmlWriter.WriteWhitespace(vbNewLine)
            xmlWriter.WriteStartElement("constants")
            xmlWriter.WriteAttributeString("version", BuildInfo.ProductVersion)
            xmlWriter.WriteWhitespace(vbNewLine & vbTab)
            xmlWriter.WriteElementString("meleehit", Double.Parse(txtMeleeHit.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
            xmlWriter.WriteWhitespace(vbNewLine & vbTab)
            xmlWriter.WriteElementString("spellhit", Double.Parse(txtSpellHit.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
            xmlWriter.WriteWhitespace(vbNewLine & vbTab)
            xmlWriter.WriteElementString("meleecap", Double.Parse(txtMeleeCap.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
            xmlWriter.WriteWhitespace(vbNewLine & vbTab)
            xmlWriter.WriteElementString("spellcap", Double.Parse(txtSpellCap.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
            xmlWriter.WriteWhitespace(vbNewLine & vbTab)
            xmlWriter.WriteElementString("expertise", Double.Parse(txtExpertise.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
            xmlWriter.WriteWhitespace(vbNewLine & vbTab)
            xmlWriter.WriteElementString("expertisecap", Double.Parse(txtExpertiseCap.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
            xmlWriter.WriteWhitespace(vbNewLine & vbTab)
            xmlWriter.WriteElementString("arp", Double.Parse(txtArP.Text).ToString(System.Globalization.CultureInfo.InvariantCulture))
            xmlWriter.WriteWhitespace(vbNewLine)
            xmlWriter.WriteEndElement()
            xmlWriter.WriteEndDocument()
            xmlWriter.Close()
            setSaved(True)
        Catch
            MessageBox.Show("An unspecified error occurred while saving.  Please reinstall DK Optimize.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1)
            End
        End Try

    End Sub

    Private Sub frmEditConstants_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        ' When the form is closing, check to see if the weights are saved.
        ' Offer the user the ability to Yes / No / Cancel and perform
        ' the appropriate action.
        Dim msgResult As DialogResult

        If saved = False Then
            msgResult = MessageBox.Show("Constants are unsaved.  Save before closing?", "DK Optimize", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1)
            If msgResult = Windows.Forms.DialogResult.Cancel Then
                e.Cancel = True
                Exit Sub
            End If
            If msgResult = Windows.Forms.DialogResult.Yes Then
                Save_Constants()
            End If
        End If
    End Sub

    Private Sub setSaved(ByVal val As Boolean)
        ' Change the status of the saved variable
        ' and update the form caption to reflect
        ' whether or not the constants are saved.
        saved = val
        If saved = True Then
            Me.Text = "DK Optimize - Edit Constants"
        Else
            Me.Text = "DK Optimize - Edit Constants*"
        End If
    End Sub

    Private Sub btnSave_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnSave.Click
        ' When the save button is clicked, save
        ' the constants by calling the Save_Constants
        ' procedure, which does the work of saving.
        Save_Constants()
    End Sub

    Private Sub textValidate(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtArP.Validating, txtExpertise.Validating, txtExpertiseCap.Validating, txtMeleeCap.Validating, txtMeleeHit.Validating, txtSpellCap.Validating, txtSpellHit.Validating
        ' When the user leaves a text cell, perform validation to make sure that
        ' the weights contain acceptable values that make sense to the overall
        ' picture.

        ' Variables to hold the sending textbox and 
        ' a message result.
        Dim myText As TextBox
        Dim msgResult As DialogResult

        ' If the user has left the text box empty, set it to the default
        ' value.  For some this is zero, for others it is a value of one.
        myText = DirectCast(sender, TextBox)
        If myText.Text = "" Then
            Select Case myText.Name
                Case "txtMeleeHit", "txtSpellHit", "txtExpertise", "txtArP"
                    myText.Text = "1"
                Case Else
                    myText.Text = "0"
            End Select
        End If

        ' Perform checks to verify that the results are numeric, that they
        ' are between the specified bounds, and that specific weights
        ' are non-zero.  If any of these checks fail, cancel validation
        ' and set the focus to the guilty control.
        If IsNumeric(myText.Text) = False Then
            msgResult = MessageBox.Show("Invalid value.  Must be numeric.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
            myText.Focus()
            Exit Sub
        End If
        If Double.Parse(myText.Text) > 1000 Or Double.Parse(myText.Text) < 0 Then
            msgResult = MessageBox.Show("Invalid value.  Must be non-negative and less than 1000.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
            myText.Focus()
            Exit Sub
        End If
        If Double.Parse(myText.Text) = 0 And (myText.Name = "txtMeleeHit" Or myText.Name = "txtSpellHit" Or myText.Name = "txtExpertise" Or myText.Name = "txtArP") Then
            msgResult = MessageBox.Show("Invalid value.  Must be greater than zero.", "DK Optimize", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1)
            myText.Focus()
            Exit Sub
        End If

        ' If the value has changed since the user entered this textbox, set
        ' the status of the saved variable to false.  This will also update
        ' the form caption.
        If prevValue <> Double.Parse(myText.Text) Then
            setSaved(False)
        End If

    End Sub

    Private Sub textEnter(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtArP.Enter, txtExpertise.Enter, txtExpertiseCap.Enter, txtMeleeCap.Enter, txtMeleeHit.Enter, txtSpellCap.Enter, txtSpellHit.Enter
        ' When a textbox is entered, record the value before editing
        ' so it can be compared to the value when exiting to determine
        ' if the constants are still saved or not.
        prevValue = Double.Parse(DirectCast(sender, TextBox).Text)
    End Sub
End Class